package socket;

import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Socket server that opens a port in local host and listens to objects
 * 
 * @author Mauro Giorda
 */

public class Server {

	private int port;
	
	private ServerSocket server;
	
	/**
	 * Non public constructor - Builds a socket from socket builder and tries to open new connection in local host at the given port.
	 * 	 
	 * @param port The port in which socket connection will be opened.
	 * 
	 * @param socketBuilder An object that builds a particular type of socket.
	 * 
	 * @throws IllegalArgumentException If the connection cannot be opened in the given port - If the port value is invalid.
	 */
	Server(int port, SocketBuilder builder){
		
		if(port > 0){
			
			this.port = port;
			
			try {
			
				server = builder.buildServer(port);
			
			} catch (Exception e) {
				
				throw new IllegalArgumentException(String.format("Could not open server in port: %s", port), e);
			}
		}
		else throw new IllegalArgumentException(String.format("Port invalid value: %s", port));
	}
	
	/**
	 * Returns server connection port.
	 * 
	 * @return port server connection port.
	 */
	public int getPort(){
		return port;
	}
	
	/**
	 * Listens to an object sent by a client to the specific port. It assumes that the object type is the expected of this server class.
	 * 
	 * @param clas The expected class type of the object being received.
	 * 
	 * @return T Reads an object sent by a client casted to the type of the class given.
	 * 
	 * @throws IllegalStateException If there is a problem in object connection's reading - If red object does not match the expected type. 
	 */
	@SuppressWarnings("unchecked")
	public <T> T recieve(Class<T> clas){
		
		try {
			
			Socket socket = server.accept();
			
			ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
			
			Object obj = in.readObject();
			
			return (T) obj;
			
		} catch (Exception e) {

			throw new IllegalStateException("Could not recieve object", e);
		}
	}
}
